# ValueService

> ValueService - это сервис, который не должен напрямую использоваться в коде тестов.
  Это механизм, который предназначен, в первую очередь, для написания функциональных матчеров,
  которые могут использовать объекты из `DataSource` и применять к ним `DataConverter` 
{style="warning"}

Для чего все это нужно. Даже на небольших проектах автотестов приходится сохранять какие-либо объекты,
получаемые в процессе выполнения тестового сценария, чтобы позже их переиспользовать.
Для этих целей используют чаще всего `HashMap` или производные структуры типа `Stash`.
Некоторые фреймворки, например, JUnit5 предоставляют свои хранилища (`ExtensionContext.Store`).
Однако, зачастую, таких хранилищ становится недостаточно.

Появляются специализированные хранилища информации для:
- простых объектов (Stash)
- сгенерированных предусловиями моделей
- свойств, которые используются в тестах

В утилитных классах появляются методы доступа к:
- справочным таблицам
- шаблонам для подстановки значений
- часто используемым таблицам в БД
- и тп

У всех этих сущностей есть один общий функционал - получить значение нужного типа по ключу.

Working with DataSources
------------------------
`ValueService` дает единый механизм для доступа ко всем этим сущностям через простой единообразный синтаксис:
```Java
String value = valueService.stringProcess("User ${[user] John} created");
```
Метод stringProcess обрабатывает входящее строковое значение и возвращает результат.
Как происходит обработка этой строки?
- Берется строковый токен `"User "`
- Далее идет конструкция обращения к источнику данных (`DataSource`) - она заключается внутри `${ }`
- Происходит поиск DataSource с именем `"user"` - это значение, заключенное в квадратных скобках
- Если `DataSource` с таким именем найден, то оттуда запрашивается значение по ключу `John`.
  Если значение запрашивается в контексте строки, то оно приводится к типу `String`.
- И к получившейся строке добавляется `" created"`

Для проекта главный источник данных может быть обозначен как источник данных по умолчанию.
Для получения данных из этого источника имя указывать не нужно.
```Java
String value = valueService.stringProcess("User ${John} created");
```
> В данном примере приведена простая текстовка, которая содержит всего одно значение из одного `DataSource`.
  Достаточно часто приходится писать, например, текстовку смс-оповещения в которую необходимо подставить:
  `имя пользователя`, `сумму`, `время`, `проверочный код`, `телефон из сущности пользователя` и т.п.
  Данный формат позволяет реализовать это минимальным количеством кода и в понятном виде.
{style="note"}

Working with DataConverters
---------------------------
Помимо получения данных из DataSource иногда возникает необходимость в конвертировании полученных значений.
Например:
- на этапе создания заказа вы сохранили в `Stash` цену товара, которая была в формате `1000.00 Р`.
- на этапе подтверждения заказа вам необходимо сравнить итоговую цену с ранее сохраненной, однако,
  на странице подтверждения эта цена в другом формате: `1 000.00 руб`.

И здесь у вас есть выбор - либо писать логику преобразования значений прямо в тесте, либо вынести ее в конвертер.
В первом случае у вас получается минимум дополнительных сущностей, но:
- код тестов усложняется
- при изменении какого-либо из форматов - все тесты придется рефакторить.

Вынос такой повторяющейся логики в конвертер - вариант более предпочтительный.
`ValueService` дает возможность использовать конвертеры прямо внутри строки.
Например, если у нас `DataSource` с пользователями возвращает объекты типа `User` и вам нужно их привести к строке не
через явный вызов `User.toString()`, а, например, вывести только фамилию.
```Java
String value = valueService.stringProcess("User @{[user to userName]${[user] John}} created");
```
Данная конструкция содержит обертку `@{[user to userName]objectToConvert}`, которая вызывает конвертер
с именем `user to userName` над сущностью, которую получаем из `DataSource` с именем `user`.

> Данные конструкции работают в любой последовательности и с неограниченной вложенностью друг в друга.
  То есть объект получаемый из одного `DataSource` может быть ключом для другого `DataSource`.
{style="note"}
